#ifndef __TOYM__NET__CHANNEL_H__
#define __TOYM__NET__CHANNEL_H__

#include "net/Callables.h"
#include "Base/noncopyable.h"
#include <memory>

namespace toym
{

namespace net
{

// 前置声明
class EventLoop;
class Poller;

class Channel: noncopyable {
public:
    Channel(int fd, EventLoop* loop);

    void setReadCallback(const ChannelReadCb_t& cb) { m_readCb = cb; }
    void setReadCallback(ChannelReadCb_t&& cb) { m_readCb = std::move(cb); }
    void setWriteCallback(const ChannelWriteCb_t& cb) { m_writeCb = cb; }
    void setWriteCallback(ChannelWriteCb_t&& cb) { m_writeCb = std::move(cb); }
    void setErrorCallback(const ChannelErrorCb_t& cb) { m_errCb = cb; }
    void setErrorCallback(ChannelErrorCb_t&& cb) { m_errCb = std::move(cb); }
    void setCloseCallback(const ChannelCloseCb_t& cb) { m_closeCb = cb; }
    void setCloseCallback(ChannelCloseCb_t&& cb) { m_closeCb = std::move(cb); }

    bool isNonEvent() { return m_events == s_nonEvent; }

    void enbaleRead() { m_events |= s_readEvent; update(); }
    void enableWrite() { m_events |= s_writeEvent; update(); }
    void disableRead() { m_events &= ~s_readEvent; update(); }
    void disableWrite() { m_events &= ~s_writeEvent; update(); }
    void disableAll() { m_events = s_nonEvent; update(); }

    // for poller
    int getIdx() { return m_idx; }
    void setIdx(int idx) { m_idx = idx; }
    int getFd() { return m_fd; }

    int getEvents() { return m_events; }

    bool isWriting() { return m_events & s_writeEvent; }

    // for poller
    void setRevnets(int revents) { m_revents = revents; }

    void handleEvents();

    void tie(const std::shared_ptr<void>& obj);


private:

    void update();
    void handleEventsWithGurad();

    int m_fd;
    int m_idx;
    ChannelReadCb_t m_readCb;
    ChannelWriteCb_t m_writeCb;
    ChannelCloseCb_t m_closeCb;
    ChannelErrorCb_t m_errCb;
    int m_events;
    int m_revents;
    EventLoop* m_loop;
    std::weak_ptr<void> m_tie;
    bool m_tied;

    static const int s_readEvent;
    static const int s_writeEvent;
    static const int s_nonEvent;
};

} // namespace net

} // namespace toym


#endif //__TOYM__NET__CHANNEL_H__